package com.cskaoyan.javase.oop3._0abstract._0introduction._1new;

/**
 * 抽象类的引入
 * 以下猫狗继承案例，是一个非常基础的继承语法的代码。思考一下Animal类的继承体系，有什么问题吗？
 * 从以下两个角度分析：
 * 1. 从代码角度上，有没有冗余代码？
 *      Animal类当中的shout方法是始终没有被调用的,它的作用是被子类继承和重写
 *      它其实不需要方法体.
 *
 * 2. 从设计角度上，在这个案例中，会存在一个`动物`对象吗？
 *      Animal是一个抽象的概念,用来表示全体动物,它不是一个具体的概念,也不需要创建它的对象
 *      而且既然它是抽象概念,也没有办法描述它的行为
 *
 * 综上所述:
 *      1.Animal类当中的shout方法应该没有方法体
 *      2.Animal类不应该创建对象,它的作用就是被继承,就是用来创建子类的
 *
 * 于是,我们首先去掉shout方法的方法体,会编译报错:
 * Missing method body, or declare abstract
 * 这句话告诉我们:
 *      一个方法,要么就有方法体,要么就声明为抽象(方法)
 *      抽象方法可以没有方法体
 *
 * 如何声明抽象方法呢?
 * [访问权限修饰符] abstract 返回值类型 方法名(形参列表);
 *
 * 直接在普通类中声明抽象方法后,会报错:
 * Abstract method in non-abstract class 抽象方法应该在抽象类中
 * Class 'Animal' must either be declared abstract or implement abstract method 'shout()' in 'Animal'
 * 普通类中是没有抽象方法的,如果有抽象方法,那它应该是一个抽象类
 *
 * 如何声明抽象类呢?
 * [访问权限修饰符] abstract class 类名{
 *     // 类体
 * }
 *
 * 声明抽象类和抽象方法后,程序就不会报错了
 * 接下来我们验证:
 *      1.Animal是抽象类,抽象类无法创建对象
 *      2.抽象类仍然是一个类,它和它的子类仍然是继承的"is-a"关系,多态现象仍然存在.
 *
 * @since 10:05
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 'Animal' is abstract; cannot be instantiated
        // Animal a = new Animal();
        testShout(new Cat());
        testShout(new Dog());
    }

    public static void testShout(Animal a){
        a.shout();
    }
}

abstract class Animal {
    // '{' or ';' expected
    public abstract void shout();
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫叫");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫");
    }
}